home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / src / Fl_win32.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-16  |  27.6 KB  |  954 lines

  1. //
  2. // "$Id: Fl_win32.cxx,v 1.33.2.14 1999/09/16 05:34:26 bill Exp $"
  3. //
  4. // WIN32-specific code for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-1999 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  24. //
  25.  
  26. // This file contains win32-specific code for fltk which is always linked
  27. // in.  Search other files for "WIN32" or filenames ending in _win32.C
  28. // for other system-specific code.
  29.  
  30. #include <config.h>
  31. #include <FL/Fl.H>
  32. #include <FL/win32.H>
  33. #include <FL/Fl_Window.H>
  34. #include <string.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <sys/types.h>
  38. #include <time.h>
  39. #include <winsock.h>
  40. #include <ctype.h>
  41.  
  42. //
  43. // WM_SYNCPAINT is an "undocumented" message, which is finally defined in
  44. // VC++ 6.0.
  45. //
  46. #ifndef WM_SYNCPAINT
  47. #  define WM_SYNCPAINT 0x0088
  48. #endif /* !WM_SYNCPAINT */
  49.  
  50. #ifndef WM_MOUSELEAVE
  51. #  define WM_MOUSELEAVE 0x02a3
  52. #endif
  53.  
  54. ////////////////////////////////////////////////////////////////
  55. // interface to poll/select call:
  56.  
  57. // fd's are only implemented for sockets.  Microsoft Windows does not
  58. // have a unified IO system, so it doesn't support select() on files,
  59. // devices, or pipes...  Also, unlike UNIX the Windows select() call
  60. // doesn't use the nfds parameter, so we don't need to keep track of
  61. // the maximum FD number...
  62.  
  63. static fd_set fdsets[3];
  64. #define POLLIN 1
  65. #define POLLOUT 4
  66. #define POLLERR 8
  67.  
  68. static int nfds = 0;
  69. static int fd_array_size = 0;
  70. static struct FD {
  71.   int fd;
  72.   short events;
  73.   void (*cb)(int, void*);
  74.   void* arg;
  75. } *fd = 0;
  76.  
  77. void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) {
  78.   remove_fd(n,events);
  79.   int i = nfds++;
  80.   if (i >= fd_array_size) {
  81.     fd_array_size = 2*fd_array_size+1;
  82.     fd = (FD*)realloc(fd, fd_array_size*sizeof(FD));
  83.   }
  84.   fd[i].fd = n;
  85.   fd[i].events = events;
  86.   fd[i].cb = cb;
  87.   fd[i].arg = v;
  88.   if (events & POLLIN) FD_SET(n, &fdsets[0]);
  89.   if (events & POLLOUT) FD_SET(n, &fdsets[1]);
  90.   if (events & POLLERR) FD_SET(n, &fdsets[2]);
  91. }
  92.  
  93. void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) {
  94.   Fl::add_fd(fd, POLLIN, cb, v);
  95. }
  96.  
  97. void Fl::remove_fd(int n, int events) {
  98.   int i,j;
  99.   for (i=j=0; i<nfds; i++) {
  100.     if (fd[i].fd == n) {
  101.       int e = fd[i].events & ~events;
  102.       if (!e) continue; // if no events left, delete this fd
  103.       fd[i].events = e;
  104.     }
  105.     // move it down in the array if necessary:
  106.     if (j<i) {
  107.       fd[j]=fd[i];
  108.     }
  109.     j++;
  110.   }
  111.   nfds = j;
  112.   if (events & POLLIN) FD_CLR(n, &fdsets[0]);
  113.   if (events & POLLOUT) FD_CLR(n, &fdsets[1]);
  114.   if (events & POLLERR) FD_CLR(n, &fdsets[2]);
  115. }
  116.  
  117. void Fl::remove_fd(int n) {
  118.   remove_fd(n, -1);
  119. }
  120.  
  121. MSG fl_msg;
  122.  
  123. int fl_ready() {
  124.   if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1;
  125.  
  126.   timeval t;
  127.   t.tv_sec = 0;
  128.   t.tv_usec = 0;
  129.   fd_set fdt[3];
  130.   fdt[0] = fdsets[0];
  131.   fdt[1] = fdsets[1];
  132.   fdt[2] = fdsets[2];
  133.   return ::select(0,&fdt[0],&fdt[1],&fdt[2],&t);
  134. }
  135.  
  136. double fl_wait(int timeout_flag, double time) {
  137.   int have_message = 0;
  138.   int timerid;
  139.  
  140.   if (nfds) {
  141.     // For WIN32 we need to poll for socket input FIRST, since
  142.     // the event queue is not something we can select() on...
  143.     timeval t;
  144.     t.tv_sec = 0;
  145.     t.tv_usec = 0;
  146.  
  147.     fd_set fdt[3];
  148.     fdt[0] = fdsets[0];
  149.     fdt[1] = fdsets[1];
  150.     fdt[2] = fdsets[2];
  151.  
  152.     if (::select(0,&fdt[0],&fdt[1],&fdt[2],&t)) {
  153.       // We got something - do the callback!
  154.       for (int i = 0; i < nfds; i ++) {
  155.     int f = fd[i].fd;
  156.     short revents = 0;
  157.     if (FD_ISSET(f,&fdt[0])) revents |= POLLIN;
  158.     if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT;
  159.     if (FD_ISSET(f,&fdt[2])) revents |= POLLERR;
  160.     if (fd[i].events & revents) fd[i].cb(f, fd[i].arg);
  161.       }
  162.     }
  163.   }
  164.  
  165.   // get the first message by waiting the correct amount of time:
  166.   if (!timeout_flag) {
  167.     // If we are monitoring sockets we need to check them periodically,
  168.     // so set a timer in this case...
  169.     if (nfds) {
  170.       // First see if there is a message waiting...
  171.       have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
  172.       if (!have_message) {
  173.     // If not then set a 1ms timer...
  174.     timerid = SetTimer(NULL, 0, 1, NULL);
  175.     GetMessage(&fl_msg, NULL, 0, 0);
  176.     KillTimer(NULL, timerid);
  177.       }
  178.     } else {
  179.       // Wait for a message...
  180.       GetMessage(&fl_msg, NULL, 0, 0);
  181.     }
  182.     have_message = 1;
  183.   } else {
  184.     // Perform the requested timeout...
  185.     have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
  186.     if (!have_message && time > 0.0) {
  187.       int t = (int)(time * 1000.0);
  188.       if (t <= 0) t = 1;
  189.       timerid = SetTimer(NULL, 0, t, NULL);
  190.       GetMessage(&fl_msg, NULL, 0, 0);
  191.       KillTimer(NULL, timerid);
  192.       have_message = 1;
  193.     }
  194.   }
  195.  
  196.   // execute it, them execute any other messages that become ready during it:
  197.   while (have_message) {
  198.     DispatchMessage(&fl_msg);
  199.     have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE);
  200.   }
  201.  
  202.   return time;
  203. }
  204.  
  205. ////////////////////////////////////////////////////////////////
  206.  
  207. int Fl::x()
  208. {
  209.   RECT r;
  210.  
  211.   SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  212.   return r.left;
  213. }
  214.  
  215. int Fl::y()
  216. {
  217.   RECT r;
  218.  
  219.   SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  220.   return r.top;
  221. }
  222.  
  223. int Fl::h()
  224. {
  225.   RECT r;
  226.  
  227.   SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  228.   return r.bottom - r.top;
  229. }
  230.  
  231. int Fl::w()
  232. {
  233.   RECT r;
  234.  
  235.   SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  236.   return r.right - r.left;
  237. }
  238.  
  239. void Fl::get_mouse(int &x, int &y) {
  240.   POINT p;
  241.   GetCursorPos(&p);
  242.   x = p.x;
  243.   y = p.y;
  244. }
  245.  
  246. ////////////////////////////////////////////////////////////////
  247.  
  248. HWND fl_capture;
  249.  
  250. static int mouse_event(Fl_Window *window, int what, int button,
  251.             WPARAM wParam, LPARAM lParam)
  252. {
  253.   static int px, py, pmx, pmy;
  254.   POINT pt;
  255.   Fl::e_x = pt.x = (signed short)LOWORD(lParam);
  256.   Fl::e_y = pt.y = (signed short)HIWORD(lParam);
  257.   ClientToScreen(fl_xid(window), &pt);
  258.   Fl::e_x_root = pt.x;
  259.   Fl::e_y_root = pt.y;
  260.   while (window->parent()) {
  261.     Fl::e_x += window->x();
  262.     Fl::e_y += window->y();
  263.     window = window->window();
  264.   }
  265.  
  266.   ulong state = Fl::e_state & 0xff0000; // keep shift key states
  267. #if 0
  268.   // mouse event reports some shift flags, perhaps save them?
  269.   if (wParam & MK_SHIFT) state |= FL_SHIFT;
  270.   if (wParam & MK_CONTROL) state |= FL_CTRL;
  271. #endif
  272.   if (wParam & MK_LBUTTON) state |= FL_BUTTON1;
  273.   if (wParam & MK_MBUTTON) state |= FL_BUTTON2;
  274.   if (wParam & MK_RBUTTON) state |= FL_BUTTON3;
  275.   Fl::e_state = state;
  276.  
  277.   switch (what) {
  278.   case 1: // double-click
  279.     if (Fl::e_is_click) {Fl::e_clicks++; goto J1;}
  280.   case 0: // single-click
  281.     Fl::e_clicks = 0;
  282.   J1:
  283.     if (!fl_capture) SetCapture(fl_xid(window));
  284.     Fl::e_keysym = FL_Button + button;
  285.     Fl::e_is_click = 1;
  286.     px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root;
  287.     return Fl::handle(FL_PUSH,window);
  288.  
  289.   case 2: // release:
  290.     if (!fl_capture) ReleaseCapture();
  291.     Fl::e_keysym = FL_Button + button;
  292.     return Fl::handle(FL_RELEASE,window);
  293.  
  294.   case 3: // move:
  295.   default: // avoid compiler warning
  296.     // MSWindows produces extra events even if mouse does not move, ignore em:
  297.     if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1;
  298.     pmx = Fl::e_x_root; pmy = Fl::e_y_root;
  299.     if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0;
  300.     return Fl::handle(FL_MOVE,window);
  301.  
  302.   }
  303. }
  304.  
  305. // convert a MSWindows VK_x to an Fltk (X) Keysym:
  306. // See also the inverse converter in Fl_get_key_win32.C
  307. // This table is in numeric order by VK:
  308. static const struct {unsigned short vk, fltk, extended;} vktab[] = {
  309.   {VK_BACK,    FL_BackSpace},
  310.   {VK_TAB,    FL_Tab},
  311.   {VK_CLEAR,    FL_KP+'5',    0xff0b/*XK_Clear*/},
  312.   {VK_RETURN,    FL_Enter,    FL_KP_Enter},
  313.   {VK_SHIFT,    FL_Shift_L,    FL_Shift_R},
  314.   {VK_CONTROL,    FL_Control_L,    FL_Control_R},
  315.   {VK_MENU,    FL_Alt_L,    FL_Alt_R},
  316.   {VK_PAUSE,    FL_Pause},
  317.   {VK_CAPITAL,    FL_Caps_Lock},
  318.   {VK_ESCAPE,    FL_Escape},
  319.   {VK_SPACE,    ' '},
  320.   {VK_PRIOR,    FL_KP+'9',    FL_Page_Up},
  321.   {VK_NEXT,    FL_KP+'3',    FL_Page_Down},
  322.   {VK_END,    FL_KP+'1',    FL_End},
  323.   {VK_HOME,    FL_KP+'7',    FL_Home},
  324.   {VK_LEFT,    FL_KP+'4',    FL_Left},
  325.   {VK_UP,    FL_KP+'8',    FL_Up},
  326.   {VK_RIGHT,    FL_KP+'6',    FL_Right},
  327.   {VK_DOWN,    FL_KP+'2',    FL_Down},
  328.   {VK_SNAPSHOT,    FL_Print},    // does not work on NT
  329.   {VK_INSERT,    FL_KP+'0',    FL_Insert},
  330.   {VK_DELETE,    FL_KP+'.',    FL_Delete},
  331.   {VK_LWIN,    FL_Meta_L},
  332.   {VK_RWIN,    FL_Meta_R},
  333.   {VK_APPS,    FL_Menu},
  334.   {VK_MULTIPLY,    FL_KP+'*'},
  335.   {VK_ADD,    FL_KP+'+'},
  336.   {VK_SUBTRACT,    FL_KP+'-'},
  337.   {VK_DECIMAL,    FL_KP+'.'},
  338.   {VK_DIVIDE,    FL_KP+'/'},
  339.   {VK_NUMLOCK,    FL_Num_Lock},
  340.   {VK_SCROLL,    FL_Scroll_Lock},
  341.   {0xba,    ';'},
  342.   {0xbb,    '='},
  343.   {0xbc,    ','},
  344.   {0xbd,    '-'},
  345.   {0xbe,    '.'},
  346.   {0xbf,    '/'},
  347.   {0xc0,    '`'},
  348.   {0xdb,    '['},
  349.   {0xdc,    '\\'},
  350.   {0xdd,    ']'},
  351.   {0xde,    '\''}
  352. };
  353. static int ms2fltk(int vk, int extended) {
  354.   static unsigned short vklut[256];
  355.   static unsigned short extendedlut[256];
  356.   if (!vklut[1]) { // init the table
  357.     unsigned int i;
  358.     for (i = 0; i < 256; i++) vklut[i] = tolower(i);
  359.     for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1));
  360.     for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0);
  361.     for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) {
  362.       vklut[vktab[i].vk] = vktab[i].fltk;
  363.       extendedlut[vktab[i].vk] = vktab[i].extended;
  364.     }
  365.     for (i = 0; i < 256; i++) if (!extendedlut[i]) extendedlut[i] = vklut[i];
  366.   }
  367.   return extended ? extendedlut[vk] : vklut[vk];
  368. }
  369.  
  370. #if USE_COLORMAP
  371. extern HPALETTE fl_select_palette(void); // in fl_color_win32.C
  372. #endif
  373.  
  374. static Fl_Window* resize_bug_fix;
  375.  
  376. static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  377. {
  378.   static char buffer[2];
  379.   static int cnt=0;
  380.  
  381.   if(uMsg == WM_SYNCPAINT) {
  382.     if(cnt) {
  383.       InvalidateRect(fl_window,0,FALSE);
  384.       cnt = 0;
  385.     } else cnt = 1;
  386.   } else if (uMsg == WM_PAINT) cnt = 0;
  387.  
  388.   fl_msg.message = uMsg;
  389.  
  390.   Fl_Window *window = fl_find(hWnd);
  391.  
  392.  STUPID_MICROSOFT:
  393.   if (window) switch (uMsg) {
  394.  
  395.   case WM_QUIT: // this should not happen?
  396.     Fl::fatal("WM_QUIT message");
  397.  
  398.   case WM_CLOSE: // user clicked close box
  399.     Fl::handle(FL_CLOSE, window);
  400.     return 0;
  401.  
  402.   case WM_PAINT: {
  403.  
  404.     // This might be a better alternative, where we fully ignore NT's
  405.     // "facilities" for painting. MS expects applications to paint according
  406.     // to a very restrictive paradigm, and this is the way I found of
  407.     // working around it. In a sense, we are using WM_PAINT simply as an
  408.     // "exposure alert", like the X event.
  409.  
  410.     Fl_X *i = Fl_X::i(window);
  411.     i->wait_for_expose = 0;
  412.     // if region == entire window we should delete i->region, else
  413.     if (window->damage()) {
  414.       if (i->region) {
  415.     InvalidateRgn(hWnd,i->region,FALSE);
  416.     GetUpdateRgn(hWnd,i->region,0);
  417.       }
  418.     } else {
  419.       if (!i->region) i->region = CreateRectRgn(0,0,0,0);
  420.       GetUpdateRgn(hWnd,i->region,0);
  421.     }
  422.     window->clear_damage(window->damage()|FL_DAMAGE_EXPOSE);
  423.     i->flush();
  424.     window->clear_damage();
  425.     // This convinces MSWindows we have painted whatever they wanted
  426.     // us to paint, and stops it from sending WM_PAINT messages.
  427.     ValidateRgn(hWnd,NULL);
  428.     } break;
  429.  
  430.   case WM_LBUTTONDOWN:  mouse_event(window, 0, 1, wParam, lParam); return 0;
  431.   case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0;
  432.   case WM_LBUTTONUP:    mouse_event(window, 2, 1, wParam, lParam); return 0;
  433.   case WM_MBUTTONDOWN:  mouse_event(window, 0, 2, wParam, lParam); return 0;
  434.   case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0;
  435.   case WM_MBUTTONUP:    mouse_event(window, 2, 2, wParam, lParam); return 0;
  436.   case WM_RBUTTONDOWN:  mouse_event(window, 0, 3, wParam, lParam); return 0;
  437.   case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0;
  438.   case WM_RBUTTONUP:    mouse_event(window, 2, 3, wParam, lParam); return 0;
  439.   case WM_MOUSEMOVE:    mouse_event(window, 3, 0, wParam, lParam); return 0;
  440.  
  441.   case WM_MOUSELEAVE:
  442.     Fl::handle(FL_LEAVE, window);
  443.     break;
  444.  
  445.   case WM_SETFOCUS:
  446.     Fl::handle(FL_FOCUS, window);
  447.     break;
  448.  
  449.   case WM_KILLFOCUS:
  450.     Fl::handle(FL_UNFOCUS, window);
  451.     Fl::flush(); // it never returns to main loop when deactivated...
  452.     break;
  453.  
  454.   case WM_SHOWWINDOW:
  455.     if (!window->parent())
  456.       Fl::handle(wParam ? FL_SHOW : FL_HIDE, window);
  457.     break;
  458.  
  459.   case WM_KEYDOWN:
  460.   case WM_SYSKEYDOWN:
  461.     // save the keysym until we figure out the characters:
  462.     Fl::e_keysym = ms2fltk(wParam,lParam&(1<<24));
  463.   case WM_KEYUP:
  464.   case WM_SYSKEYUP:
  465.     TranslateMessage(&fl_msg); // always returns 1!!!
  466.     // TranslateMessage is supposed to return true only if it turns
  467.     // into another message, but it seems to always return 1 on my
  468.     // NT machine.  So I will instead peek to see if there is a
  469.     // character message in the queue, I hope this can only happen
  470.     // if the translation worked:
  471.     if (PeekMessage(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, 1)) {
  472.       uMsg = fl_msg.message;
  473.       wParam = fl_msg.wParam;
  474.       lParam = fl_msg.lParam;
  475.       goto STUPID_MICROSOFT;
  476.     }
  477.     // otherwise use it as a 0-character key...
  478.   case WM_DEADCHAR:
  479.   case WM_SYSDEADCHAR:
  480.   case WM_CHAR:
  481.   case WM_SYSCHAR:
  482.     {ulong state = Fl::e_state & 0xff000000; // keep the mouse button state
  483.      // if GetKeyState is expensive we might want to comment some of these out:
  484.       if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT;
  485.       if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK;
  486.       if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL;
  487.       // Alt gets reported for the Alt-GR switch on foreign keyboards.
  488.       // so we need to check the event as well to get it right:
  489.       if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU)
  490.     && uMsg != WM_CHAR) state |= FL_ALT;
  491.       if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK;
  492.       if (GetKeyState(VK_LWIN)&~1 || GetKeyState(VK_RWIN)&~1) state |= FL_META;
  493.       if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
  494.       Fl::e_state = state;}
  495.     if (lParam & (1<<31)) goto DEFAULT; // ignore up events after fixing shift
  496.     if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
  497.       buffer[0] = char(wParam);
  498.       Fl::e_length = 1;
  499.     } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
  500.       buffer[0] = Fl::e_keysym-FL_KP;
  501.       Fl::e_length = 1;
  502.     } else {
  503.       buffer[0] = 0;
  504.       Fl::e_length = 0;
  505.     }
  506.     Fl::e_text = buffer;
  507.     // for (int i = lParam&0xff; i--;)
  508.     while (window->parent()) window = window->window();
  509.     if (Fl::handle(FL_KEYBOARD,window)) return 0;
  510.     break;
  511.  
  512.   case WM_GETMINMAXINFO:
  513.     Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam);
  514.     break;
  515.  
  516.   case WM_SIZE:
  517.     if (!window->parent()) {
  518.       if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) {
  519.     Fl::handle(FL_HIDE, window);
  520.       } else {
  521.     Fl::handle(FL_SHOW, window);
  522.     resize_bug_fix = window;
  523.     window->size(LOWORD(lParam), HIWORD(lParam));
  524.       }
  525.     }
  526.     break;
  527.  
  528.   case WM_MOVE:
  529.     resize_bug_fix = window;
  530.     window->position(LOWORD(lParam), HIWORD(lParam));
  531.     break;
  532.  
  533.   case WM_SETCURSOR:
  534.     if (LOWORD(lParam) == HTCLIENT) {
  535.       while (window->parent()) window = window->window();
  536.       SetCursor(Fl_X::i(window)->cursor);
  537.       return 0;
  538.     }
  539.     break;
  540.  
  541. #if USE_COLORMAP
  542.   case WM_QUERYNEWPALETTE :
  543.     fl_GetDC(hWnd);
  544.     if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE);
  545.     break;
  546.  
  547.   case WM_PALETTECHANGED:
  548.     fl_GetDC(hWnd);
  549.     if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc);
  550.     break;
  551.  
  552.   case WM_CREATE :
  553.     fl_GetDC(hWnd);
  554.     fl_select_palette();
  555.     break;
  556.  
  557. #endif
  558.  
  559.   default:
  560.   DEFAULT:
  561.     if (Fl::handle(0,0)) return 0;
  562.     break;
  563.   }
  564.  
  565.   return DefWindowProc(hWnd, uMsg, wParam, lParam);
  566. }
  567.  
  568. ////////////////////////////////////////////////////////////////
  569. // This function gets the dimensions of the top/left borders and
  570. // the title bar, if there is one, based on the FL_BORDER, FL_MODAL
  571. // and FL_NONMODAL flags, and on the window's size range.
  572. // It returns the following values:
  573. //
  574. // value | border | title bar
  575. //   0   |  none  |   no
  576. //   1   |  fix   |   yes
  577. //   2   |  size  |   yes
  578.  
  579. int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) {
  580.   int W, H, xoff, yoff, dx, dy;
  581.   int ret = bx = by = bt = 0;
  582.   if (w->border() && !w->parent()) {
  583.     if (w->maxw != w->minw || w->maxh != w->minh) {
  584.       ret = 2;
  585.       bx = GetSystemMetrics(SM_CXSIZEFRAME);
  586.       by = GetSystemMetrics(SM_CYSIZEFRAME);
  587.     } else {
  588.       ret = 1;
  589.       bx = GetSystemMetrics(SM_CXFIXEDFRAME);
  590.       by = GetSystemMetrics(SM_CYFIXEDFRAME);
  591.     }
  592.     bt = GetSystemMetrics(SM_CYCAPTION);
  593.   }
  594.   //The coordinates of the whole window, including non-client area
  595.   xoff = bx;
  596.   yoff = by + bt;
  597.   dx = 2*bx;
  598.   dy = 2*by + bt;
  599.   X = w->x()-xoff;
  600.   Y = w->y()-yoff;
  601.   W = w->w()+dx;
  602.   H = w->h()+dy;
  603.  
  604.   //Proceed to positioning the window fully inside the screen, if possible
  605.   //Make border's lower right corner visible
  606.   if (Fl::w() < X+W) X = Fl::w() - W;
  607.   if (Fl::h() < Y+H) Y = Fl::h() - H;
  608.   //Make border's upper left corner visible
  609.   if (X<0) X = 0;
  610.   if (Y<0) Y = 0;
  611.   //Make client area's lower right corner visible
  612.   if (Fl::w() < X+dx+ w->w()) X = Fl::w() - w->w() - dx;
  613.   if (Fl::h() < Y+dy+ w->h()) Y = Fl::h() - w->h() - dy;
  614.   //Make client area's upper left corner visible
  615.   if (X+xoff < 0) X = -xoff;
  616.   if (Y+yoff < 0) Y = -yoff;
  617.   //Return the client area's top left corner in (X,Y)
  618.   X+=xoff;
  619.   Y+=yoff;
  620.  
  621.   return ret;
  622. }
  623.  
  624. ////////////////////////////////////////////////////////////////
  625.  
  626. void Fl_Window::resize(int X,int Y,int W,int H) {
  627.   UINT flags = SWP_NOSENDCHANGING | SWP_NOZORDER;
  628.   int is_a_resize = (W != w() || H != h());
  629.   int resize_from_program = (this != resize_bug_fix);
  630.   if (!resize_from_program) resize_bug_fix = 0;
  631.   if (X != x() || Y != y()) set_flag(FL_FORCE_POSITION);
  632.     else {if (!is_a_resize) return; flags |= SWP_NOMOVE;}
  633.   if (is_a_resize) {
  634.     Fl_Group::resize(X,Y,W,H);
  635.     if (shown()) {redraw(); i->wait_for_expose = 1;}
  636.   } else {
  637.     x(X); y(Y);
  638.     flags |= SWP_NOSIZE;
  639.   }
  640.   if (resize_from_program && shown()) {
  641.     int dummy, bt, bx, by;
  642.     //Ignore window managing when resizing, so that windows (and more
  643.     //specifically menus) can be moved offscreen.
  644.     if (Fl_X::fake_X_wm(this, dummy, dummy, bt, bx, by)) {
  645.       X -= bx;
  646.       Y -= by+bt;
  647.       W += 2*bx;
  648.       H += 2*by+bt;
  649.     }
  650.     SetWindowPos(i->xid, 0, X, Y, W, H, flags);
  651.   }
  652. }
  653.  
  654. ////////////////////////////////////////////////////////////////
  655.  
  656. void fl_fix_focus(); // in Fl.C
  657.  
  658. char fl_show_iconic;    // hack for Fl_Window::iconic()
  659. // int fl_background_pixel = -1; // color to use for background
  660. HCURSOR fl_default_cursor;
  661. int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
  662.  
  663. Fl_X* Fl_X::make(Fl_Window* w) {
  664.   Fl_Group::current(0); // get rid of very common user bug: forgot end()
  665.  
  666.   const char* class_name = w->xclass();
  667.   if (!class_name) class_name = "FLTK"; // create a "FLTK" WNDCLASS
  668.  
  669.   WNDCLASSEX wc;
  670.   // Documentation states a device context consumes about 800 bytes
  671.   // of memory... so who cares? If 800 bytes per window is what it
  672.   // takes to speed things up, I'm game.
  673.   //wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS;
  674.   wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
  675.   wc.lpfnWndProc = (WNDPROC)WndProc;
  676.   wc.cbClsExtra = wc.cbWndExtra = 0;
  677.   wc.hInstance = fl_display;
  678.   if (!w->icon())
  679.     w->icon((void *)LoadIcon(NULL, IDI_APPLICATION));
  680.   wc.hIcon = wc.hIconSm = (HICON)w->icon();
  681.   wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW);
  682.   //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
  683.   //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
  684.   wc.hbrBackground = NULL;
  685.   wc.lpszMenuName = NULL;
  686.   wc.lpszClassName = class_name;
  687.   wc.cbSize = sizeof(WNDCLASSEX);
  688.   RegisterClassEx(&wc);
  689.  
  690.   HWND parent;
  691.   DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  692.   DWORD styleEx = WS_EX_LEFT;
  693.  
  694.   int xp = w->x();
  695.   int yp = w->y();
  696.   int wp = w->w();
  697.   int hp = w->h();
  698.  
  699.   if (w->parent()) {
  700.     style = WS_CHILD;
  701.     styleEx = WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
  702.     parent = fl_xid(w->window());
  703.   } else {
  704.     if (!w->size_range_set) {
  705.       if (w->resizable()) {
  706.     Fl_Widget *o = w->resizable();
  707.     int minw = o->w(); if (minw > 100) minw = 100;
  708.     int minh = o->h(); if (minh > 100) minh = 100;
  709.     w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0);
  710.       } else {
  711.     w->size_range(w->w(), w->h(), w->w(), w->h());
  712.       }
  713.     }
  714.     styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT;
  715.     int xwm = xp , ywm = yp , bt, bx, by;
  716.     switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) {
  717.       // No border (user for menus)
  718.       case 0: style |= WS_POPUP; break;
  719.  
  720.       // Thin border and title bar
  721.       case 1: style |= WS_DLGFRAME | WS_CAPTION; break;
  722.  
  723.       // Thick, resizable border and title bar, with maximize button
  724.       case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break;
  725.     }
  726.     if (by+bt) {
  727.       if (!w->non_modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX;
  728.       wp += 2*bx;
  729.       hp += 2*by+bt;
  730.     }
  731.     if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) {
  732.       xp = yp = CW_USEDEFAULT;
  733.     } else {
  734.       if (!Fl::grab()) {
  735.     xp = xwm; yp = ywm;
  736.         w->x(xp);w->y(yp);
  737.       }
  738.       xp -= bx;
  739.       yp -= by+bt;
  740.     }
  741.  
  742.     parent = 0;
  743.     if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) {
  744.       // find some other window to be "transient for":
  745.       Fl_Window* w = Fl_X::first->w;
  746.       while (w->parent()) w = w->window();
  747.       parent = fl_xid(w);
  748.     }
  749.   }
  750.  
  751.   Fl_X* x = new Fl_X;
  752.   x->other_xid = 0;
  753.   x->setwindow(w);
  754.   x->region = 0;
  755.   x->private_dc = 0;
  756.   x->cursor = fl_default_cursor;
  757.   x->xid = CreateWindowEx(
  758.     styleEx,
  759.     class_name, w->label(), style,
  760.     xp, yp, wp, hp,
  761.     parent,
  762.     NULL, // menu
  763.     fl_display,
  764.     NULL // creation parameters
  765.     );
  766.   x->next = Fl_X::first;
  767.   Fl_X::first = x;
  768.  
  769.   x->wait_for_expose = 1;
  770.   w->set_visible();
  771.   w->handle(FL_SHOW); // get child windows to appear
  772.   w->redraw(); // force draw to happen
  773.   // If we've captured the mouse, we dont want do activate any
  774.   // other windows from the code, or we loose the capture.
  775.   ShowWindow(x->xid, fl_show_iconic ? SW_SHOWMINNOACTIVE :
  776.              fl_capture? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
  777.   fl_show_iconic = 0;
  778.   if (w->modal()) {Fl::modal_ = w; fl_fix_focus();}
  779.   return x;
  780. }
  781.  
  782. ////////////////////////////////////////////////////////////////
  783.  
  784. HINSTANCE fl_display = GetModuleHandle(NULL);
  785.  
  786. //
  787. // This WinMain() function can be overridden by an application and
  788. // is provided for compatibility with programs written for other
  789. // operating systems that conform to the ANSI standard entry point
  790. // "main()".  This will allow you to build a WIN32 Application
  791. // without any special settings.
  792. //
  793. // Because of problems with the Microsoft Visual C++ header files
  794. // and/or compiler, you cannot have a WinMain function in a DLL.
  795. // I don't know why.  Thus, this nifty feature is only available
  796. // if you link to the static library.
  797. //
  798. // Currently the debug version of this library will create a
  799. // console window for your application so you can put printf()
  800. // statements for debugging or informational purposes.  Ultimately
  801. // we want to update this to always use the parent's console,
  802. // but at present we have not identified a function or API in
  803. // Microsoft(r) Windows(r) that allows for it.
  804. //
  805.  
  806. #if !defined(FL_DLL) && !defined(__GNUC__)
  807.  
  808. extern "C" int fl_call_main();
  809.  
  810. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  811.                              LPSTR lpCmdLine, int nCmdShow) {
  812.   // Save the current instance in the fl_display variable...
  813.   fl_display = hInstance;
  814.  
  815. #ifdef _DEBUG
  816.   // If we are using compiling in debug mode, open a console window so
  817.   // we can see any printf's, etc...
  818.   //
  819.   // While we can detect if the program was run from the command-line -
  820.   // look at the CMDLINE environment variable, it will be "WIN" for
  821.   // programs started from the GUI - the shell seems to run all WIN32
  822.   // applications in the background anyways...
  823.  
  824.   AllocConsole();
  825.   freopen("conin$", "r", stdin);
  826.   freopen("conout$", "w", stdout);
  827.   freopen("conout$", "w", stderr);
  828. #endif // _DEBUG
  829.  
  830.   // Run the standard main entry point function...
  831.   return fl_call_main();
  832. }
  833.  
  834. #endif /* !FL_DLL && !__GNUC__ */
  835.  
  836. ////////////////////////////////////////////////////////////////
  837.  
  838. void Fl_Window::size_range_() {
  839.   size_range_set = 1;
  840. }
  841.  
  842. void Fl_X::set_minmax(LPMINMAXINFO minmax)
  843. {
  844.   int td, wd, hd, dummy;
  845.  
  846.   fake_X_wm(w, dummy, dummy, td, wd, hd);
  847.   wd *= 2;
  848.   hd *= 2;
  849.   hd += td;
  850.  
  851.   minmax->ptMinTrackSize.x = w->minw + wd;
  852.   minmax->ptMinTrackSize.y = w->minh + hd;
  853.   if (w->maxw) {
  854.     minmax->ptMaxTrackSize.x = w->maxw + wd;
  855.     minmax->ptMaxSize.x = w->maxw + wd;
  856.   }
  857.   if (w->maxh) {
  858.     minmax->ptMaxTrackSize.y = w->maxh + hd;
  859.     minmax->ptMaxSize.y = w->maxh + hd;
  860.   }
  861. }
  862.  
  863. ////////////////////////////////////////////////////////////////
  864.  
  865. #include <FL/filename.H> // need so FL_EXPORT filename_name works
  866.  
  867. // returns pointer to the filename, or null if name ends with '/'
  868. const char *filename_name(const char *name) {
  869.   const char *p,*q;
  870.   q = name;
  871.   if (q[0] && q[1]==':') q += 2; // skip leading drive letter
  872.   for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1;
  873.   return q;
  874. }
  875.  
  876. void Fl_Window::label(const char *name,const char *iname) {
  877.   Fl_Widget::label(name);
  878.   iconlabel_ = iname;
  879.   if (shown() && !parent()) {
  880.     if (!name) name = "";
  881.     SetWindowText(i->xid, name);
  882.     // if (!iname) iname = filename_name(name);
  883.     // should do something with iname here...
  884.   }
  885. }
  886.  
  887. ////////////////////////////////////////////////////////////////
  888. // Implement the virtual functions for the base Fl_Window class:
  889.  
  890. // If the box is a filled rectangle, we can make the redisplay *look*
  891. // faster by using X's background pixel erasing.  We can make it
  892. // actually *be* faster by drawing the frame only, this is done by
  893. // setting fl_boxcheat, which is seen by code in fl_drawbox.C:
  894. // For WIN32 it looks like all windows share a background color, so
  895. // I use FL_GRAY for this and only do this cheat for windows that are
  896. // that color.
  897. // Actually it is totally disabled.
  898. // Fl_Widget *fl_boxcheat;
  899. //static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);}
  900.  
  901. void Fl_Window::show() {
  902.   if (!shown()) {
  903.     // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color());
  904.     Fl_X::make(this);
  905.   } else {
  906.     // Once again, we would lose the capture if we activated the window.
  907.     if (IsIconic(i->xid)) OpenIcon(i->xid);
  908.     if (!fl_capture) BringWindowToTop(i->xid);
  909.     //ShowWindow(i->xid,fl_capture?SW_SHOWNOACTIVATE:SW_RESTORE);
  910.   }
  911. }
  912.  
  913. Fl_Window *Fl_Window::current_;
  914. // the current context
  915. HDC fl_gc = 0;
  916. // the current window handle, initially set to -1 so we can correctly
  917. // allocate fl_GetDC(0)
  918. HWND fl_window = (HWND)-1;
  919.  
  920. // Here we ensure only one GetDC is ever in place.
  921. HDC fl_GetDC(HWND w) {
  922.   if (fl_gc) {
  923.     if (w == fl_window) return fl_gc;
  924.     ReleaseDC(fl_window, fl_gc);
  925.   }
  926.   fl_gc = GetDC(w);
  927.   fl_window = w;
  928.   // calling GetDC seems to always reset these: (?)
  929.   SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT);
  930.   SetBkMode(fl_gc, TRANSPARENT);
  931.   return fl_gc;
  932. }
  933.  
  934. // make X drawing go into this window (called by subclass flush() impl.)
  935. void Fl_Window::make_current() {
  936.   fl_GetDC(fl_xid(this));
  937.  
  938. #if USE_COLORMAP
  939.   // Windows maintains a hardware and software color palette; the
  940.   // SelectPalette() call updates the current soft->hard mapping
  941.   // for all drawing calls, so we must select it here before any
  942.   // code does any drawing...
  943.  
  944.   fl_select_palette();
  945. #endif // USE_COLORMAP
  946.  
  947.   current_ = this;
  948.   fl_clip_region(0);
  949. }
  950.  
  951. //
  952. // End of "$Id: Fl_win32.cxx,v 1.33.2.14 1999/09/16 05:34:26 bill Exp $".
  953. //
  954.